#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind/bind.hpp>
#include <memory>
#include <string>

using boost::asio::ip::tcp;

// TCP 服务器示例
// 演示如何创建异步 TCP 服务器

class TcpConnection : public std::enable_shared_from_this<TcpConnection> {
private:
    tcp::socket socket_;
    std::string message_;

public:
    typedef std::shared_ptr<TcpConnection> pointer;

    static pointer create(boost::asio::io_context& io_context) {
        return pointer(new TcpConnection(io_context));
    }

    tcp::socket& socket() {
        return socket_;
    }

    void start() {
        message_ = "Hello from Boost.Asio TCP Server!\n";

        boost::asio::async_write(socket_, boost::asio::buffer(message_),
            boost::bind(&TcpConnection::handle_write, shared_from_this(),
                boost::asio::placeholders::error,
                boost::asio::placeholders::bytes_transferred));

        // 开始读取客户端数据
        start_read();
    }

private:
    TcpConnection(boost::asio::io_context& io_context) : socket_(io_context) {}

    void start_read() {
        auto self = shared_from_this();
        boost::asio::async_read_until(socket_, buffer_, "\n",
            [self, this](boost::system::error_code ec, std::size_t length) {
                if (!ec) {
                    std::istream is(&buffer_);
                    std::string line;
                    std::getline(is, line);

                    std::cout << "Received from client: " << line << std::endl;

                    // 回显消息
                    std::string response = "Echo: " + line + "\n";
                    boost::asio::async_write(socket_, boost::asio::buffer(response),
                        [self](boost::system::error_code ec, std::size_t /*length*/) {
                            if (!ec) {
                                // 继续读取
                                self->start_read();
                            }
                        });
                } else {
                    std::cout << "Client disconnected: " << ec.message() << std::endl;
                }
            });
    }

    void handle_write(const boost::system::error_code& error,
                      size_t bytes_transferred) {
        if (!error) {
            std::cout << "Sent " << bytes_transferred << " bytes to client" << std::endl;
        } else {
            std::cout << "Write error: " << error.message() << std::endl;
        }
    }

    boost::asio::streambuf buffer_;
};

class TcpServer {
private:
    boost::asio::io_context& io_context_;
    tcp::acceptor acceptor_;

public:
    TcpServer(boost::asio::io_context& io_context, int port)
        : io_context_(io_context),
          acceptor_(io_context, tcp::endpoint(tcp::v4(), port)) {
        start_accept();
    }

private:
    void start_accept() {
        TcpConnection::pointer new_connection =
            TcpConnection::create(io_context_);

        acceptor_.async_accept(new_connection->socket(),
            boost::bind(&TcpServer::handle_accept, this, new_connection,
                boost::asio::placeholders::error));
    }

    void handle_accept(TcpConnection::pointer new_connection,
                       const boost::system::error_code& error) {
        if (!error) {
            std::cout << "New client connected!" << std::endl;
            new_connection->start();
        } else {
            std::cout << "Accept error: " << error.message() << std::endl;
        }

        start_accept();
    }
};

// 简单的同步服务器示例
void simple_server_example(int port) {
    try {
        boost::asio::io_context io_context;
        tcp::acceptor acceptor(io_context, tcp::endpoint(tcp::v4(), port));

        std::cout << "Simple server listening on port " << port << std::endl;
        std::cout << "Connect with: telnet localhost " << port << std::endl;

        while (true) {
            tcp::socket socket(io_context);
            acceptor.accept(socket);

            std::cout << "Client connected!" << std::endl;

            std::string message = "Welcome to Simple Boost.Asio Server!\n";
            boost::system::error_code ignored_error;
            boost::asio::write(socket, boost::asio::buffer(message), ignored_error);

            // 读取客户端数据并回显
            for (;;) {
                std::array<char, 128> buf;
                boost::system::error_code error;

                size_t len = socket.read_some(boost::asio::buffer(buf), error);

                if (error == boost::asio::error::eof) {
                    std::cout << "Client disconnected" << std::endl;
                    break; // 连接关闭
                } else if (error) {
                    throw boost::system::system_error(error);
                }

                std::string received(buf.data(), len);
                std::cout << "Received: " << received;

                // 回显
                std::string echo = "Echo: " + received;
                boost::asio::write(socket, boost::asio::buffer(echo), ignored_error);
            }
        }
    } catch (std::exception& e) {
        std::cerr << "Server exception: " << e.what() << std::endl;
    }
}

int main(int argc, char* argv[]) {
    try {
        std::cout << "=== Boost.Asio TCP Server Examples ===" << std::endl;

        int port = 12345;
        if (argc > 1) {
            port = std::atoi(argv[1]);
        }

        std::cout << "Choose server type:" << std::endl;
        std::cout << "1. Simple synchronous server" << std::endl;
        std::cout << "2. Asynchronous server" << std::endl;
        std::cout << "Enter choice (1 or 2): ";

        int choice;
        std::cin >> choice;

        if (choice == 1) {
            simple_server_example(port);
        } else {
            boost::asio::io_context io_context;
            TcpServer server(io_context, port);

            std::cout << "Async server listening on port " << port << std::endl;
            std::cout << "Connect with: telnet localhost " << port << std::endl;
            std::cout << "Press Ctrl+C to stop the server" << std::endl;

            io_context.run();
        }

    } catch (std::exception& e) {
        std::cerr << "Exception: " << e.what() << std::endl;
    }

    return 0;
}
